package com.quan.commons.core.utils;

import com.quan.commons.core.properties.SystemValueProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;

/**
 * JWTToken工具类
 * @author yhaoquan
 */
@Slf4j
public class JwtUtils {


    /**
     * 使用HS256签名算法和秘钥生成最终的Token,claims中是有效载荷
     * <br>Map<String, Object> claims = new HashMap<String, Object>() ;
     * <br>claims.put("sub", "zhangsan") ;
     * <br>claims.put("ctime", DateUtils.getMillis(new Date()));
     * <br>claims.put("exp", DateUtils.addMinute(3));
     * @param claims    有效载荷
     * @param jwtSecret 秘钥
     * @return
     */
    public static String createToken(Map<String, Object> claims, String jwtSecret) {
        final SystemValueProperties properties = SpringContextHolder.getBean(SystemValueProperties.class);

        final Long timeout = properties.getJwt().getTimeout() * 60 * 60 * 24;

        String jwtToken = Jwts.builder()
                // 设置头部信息
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                // token主体部分，存储用户信息
                .setClaims(claims)

                // 设置过期时间
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + timeout))

                .signWith(SignatureAlgorithm.HS256, jwtSecret)
                .compact();

        return jwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @param jwtSecret
     * @return
     */
    public static boolean checkToken(String jwtToken, String jwtSecret) {
        if (StringUtils.isBlank(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(jwtSecret).parse(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     * @param request
     * @param jwtSecret
     * @return
     */
    public static boolean checkToken(HttpServletRequest request, String jwtSecret) {
        try {
            final String jwtToken = request.getHeader("token");
            if (StringUtils.isBlank(jwtToken)) return false;
            Jwts.parser().setSigningKey(jwtSecret).parse(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 解析token，获取全部有效载荷（JWT全部信息）
     * @param token
     * @param jwtSecret 秘钥
     * @return
     */
    public static Jws<Claims> parse(String token, String jwtSecret) {
        try {
            Jws<Claims> claimsParse = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            return claimsParse;
        } catch (Exception e) {
            log.error("Token解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析token获取用户ID
     * @param token
     * @param jwtSecret
     * @return
     */
    public static String getUserId(String token, String jwtSecret) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            Claims claimsJwt = claims.getBody();
            return claimsJwt.get("id").toString();
        } catch (Exception e) {
            log.error("Token解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析token获取用户名称
     * @param token
     * @param jwtSecret
     * @return
     */
    public static String getUserName(String token, String jwtSecret) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            Claims claimsJwt = claims.getBody();
            return claimsJwt.get("username").toString();
        } catch (Exception e) {
            log.error("Token解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析token获取用户完整信息
     * @param token
     * @param jwtSecret
     * @return
     */
    public static String getUser(String token) {
        final SystemValueProperties properties = SpringContextHolder.getBean(SystemValueProperties.class);
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(properties.getJwt().getSecret()).parseClaimsJws(token);
            Claims claimsJwt = claims.getBody();
            return claimsJwt.get("user").toString();
        } catch (Exception e) {
            log.error("Token解析失败：{}", e.getMessage());
            return null;
        }
    }

}
